
import { EOChild, fragment, FragmentNode } from '../mve/childrenBuilder'
import { BuildResult } from '../mve/util'
import { dom, DOMNode, domText, DOMTextNode, EventMap, InitFun, svg } from './index'

/**
 * 简单的tsx支撑
 * 如在tsconfig中配置
		"jsx": "react",
		"jsxFactory":"createElement",
 * 需要的地方导入
		import { createElement,Dom,Fragment,JSX, Svg, SvgFragment } from 'mve-dom/tsxSupport'
 * 可能需要全局导入
		declare namespace JSX {
			type IntrinsicElements=import("mve-dom/tsxSupport").JSX.IntrinsicElements
			type Element=import("mve-dom/tsxSupport").JSX.Element
			type ElementChildrenAttribute=import('mve-dom/tsxSupport').JSX.ElementChildrenAttribute
		}
 */

export function createElement<A extends (...vs: any[]) => any>(type: A, ...vs: Parameters<A>): ReturnType<A> {
	return type.apply(null, vs)
}

export type TsxChild = string | number | boolean | EOChild<Node>
function isEOChild(v: TsxChild): v is EOChild<Node> {
	return typeof (v) == 'function'
}

export interface DOMTsxProp extends Omit<DOMNode, 'children'> {
	children?: TsxChild | TsxChild[]
}
export function Dom(props: DOMTsxProp, ...children: TsxChild[]) {
	props.children = mergeFromTsxChildren(props.children, children)
	return dom(props as DOMNode)
}

export function fromTsxChild(child: TsxChild) {
	if (isEOChild(child)) {
		return child
	} else {
		//字符串、布尔、数字的情况
		return domText({
			text: child + ""
		})
	}
}
export function fromTsxChildren(children: TsxChild[]) {
	const length = children.length
	for (let i = 0; i < length; i++) {
		const child = children[i]
		children[i] = fromTsxChild(child)
	}
	return children as EOChild<Node>[]
}

export function mergeFromTsxChildren(childrenA: TsxChild | TsxChild[] | void, childrenB: TsxChild[]) {
	if (childrenA) {
		const allChildren = mb.Array.isArray(childrenA) ? fromTsxChildren(childrenA) : [fromTsxChild(childrenA)]
		for (let child of childrenB) {
			allChildren.push(fromTsxChild(child))
		}
		return allChildren
	} else {
		return fromTsxChildren(childrenB) as EOChild<Node>[]
	}
}

export function Fragment(props?: {
	init?: BuildResult
	children?: TsxChild | TsxChild[]
}, ...children: TsxChild[]) {
	props = props || {}
	props.children = mergeFromTsxChildren(props.children, children)
	return fragment(props as FragmentNode<Node>)
}

export interface SvgTsxProp extends Omit<DOMNode, 'children'> {
	type: string
	children?: EOChild<Node> | EOChild<Node>[]
}

export function Svg(props: SvgTsxProp, ...children: EOChild<Node>[]) {
	props.children = mergeFromEOChild(props.children, children)
	return svg(props as DOMNode)
}

export function mergeFromEOChild(childrenA: EOChild<Node> | EOChild<Node>[] | void, childrenB: EOChild<Node>[]) {
	if (childrenA) {
		const allChildren = mb.Array.isArray(childrenA) ? childrenA : [childrenA]
		for (let child of childrenB) {
			allChildren.push(child)
		}
		return allChildren
	} else {
		return childrenB
	}
}

export function SvgFragment(props?: {
	init?: BuildResult
	children?: EOChild<Node> | EOChild<Node>[]
}, ...children: EOChild<Node>[]) {
	props = props || {}
	props.children = mergeFromEOChild(props.children, children)
	return fragment(props as FragmentNode<Node>)
}

type TextType = string | number | boolean
export type TextChild = (() => TextType) | TextType
export function Text(props?: {
	init?: InitFun | InitFun[]
	event?: EventMap
	children?: TextChild | TextChild[]
}, ...children: TextChild[]) {
	props = props || {}
	const nprops = props as DOMTextNode
	nprops.text = mergeFromTextChild(props.children, children)
	return domText(nprops)
}

export function mergeFromTextChild(childrenA: TextChild | TextChild[] | undefined, childrenB: TextChild[]) {
	let isAllText = true
	const allChildren = childrenA ? (Array.isArray(childrenA) ? childrenA : [childrenA]) : []
	for (const child of allChildren) {
		if (typeof (child) == 'function') {
			isAllText = false
		}
	}
	for (const child of childrenB) {
		allChildren.push(child)
		if (typeof (child) == 'function') {
			isAllText = false
		}
	}
	if (allChildren.length > 0) {
		if (allChildren.length == 1) {
			return allChildren[0]
		} else {
			if (isAllText) {
				return allChildren.join("")
			} else {
				for (let i = 0; i < allChildren.length; i++) {
					allChildren[i] = strToFun(allChildren[i])
				}
				const transChildren = allChildren as (() => TextType)[]
				return function () {
					return transChildren.map(child => child()).join("")
				}
			}
		}
	} else {
		return ""
	}
}
export function strToFun<T>(child: T | (() => T)): () => T {
	if (typeof (child) != 'function') {
		return function () {
			return child
		}
	}
	return child as () => T
}


export namespace JSX {
	/**禁止所有内建小写元素 */
	export interface IntrinsicElements {
	}
	/**与mve-core核心类型的兼容性 */
	export type Element = EOChild<Node>
	/**
	 * TSX内容元素类型，需要先声明
	 */
	export interface ElementChildrenAttribute {
		children: any// specify children name to use
	}
}